package com.sunk.mybatis.mymybatis.Configuration;

/**
 * @Author: Sunk 673116067@qq.com
 * @Date: 2018/10/10 15:27
 * @Description:
 */

import ch.qos.logback.core.spi.ScanException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;

/**
 * 读取与解析配置信息，并返回处理后的Environment
 */
public class MyConfiguration {
    private static ClassLoader loader = ClassLoader.getSystemClassLoader();

    private static ArrayList<Object> scanFiles = new ArrayList<Object>();
    /**linkedList实现**/
    private static LinkedList<File> queueFiles = new LinkedList<File>();

    public static String preffix="mybatis";

    //存放xml和interface对应关系
    public static Map<String,MapperBean> map=new HashMap();
    static {
        try {
            System.out.println(scanFilesWithNoRecursion(Class.class.getClass().getResource("/").getPath() +"/mybatis"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 读取xml信息并处理
     */
    public Connection build(String resource){
        try {
            InputStream stream = loader.getResourceAsStream(resource);
            SAXReader reader = new SAXReader();
            Document document = reader.read(stream);
            Element root = document.getRootElement();
            return evalDataSource(root);
        } catch (Exception e) {
            throw new RuntimeException("error occured while evaling xml " + resource);
        }
    }

    private  Connection evalDataSource(Element node) throws ClassNotFoundException {
        if (!node.getName().equals("database")) {
            throw new RuntimeException("root should be <database>");
        }
        String driverClassName = null;
        String url = null;
        String username = null;
        String password = null;
        //获取属性节点
        for (Object item : node.elements("property")) {
            Element i = (Element) item;
            String value = getValue(i);
            String name = i.attributeValue("name");
            if (name == null || value == null) {
                throw new RuntimeException("[database]: <property> should contain name and value");
            }
            //赋值
            switch (name) {
                case "url" : url = value; break;
                case "username" : username = value; break;
                case "password" : password = value; break;
                case "driverClassName" : driverClassName = value; break;
                default : throw new RuntimeException("[database]: <property> unknown name");
            }
        }

        Class.forName(driverClassName);
        Connection connection = null;
        try {
            //建立数据库链接
            connection = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return connection;
    }

    //获取property属性的值,如果有value值,则读取 没有设置value,则读取内容
    private  String getValue(Element node) {
        return node.hasContent() ? node.getText() : node.attributeValue("value");
    }



    @SuppressWarnings("rawtypes")
    public static MapperBean readMapper(String path){
        MapperBean mapper = new MapperBean();
        try{
            InputStream stream = loader.getResourceAsStream(path);
            SAXReader reader = new SAXReader();
            Document document = reader.read(stream);
            Element root = document.getRootElement();
            mapper.setInterfaceName(root.attributeValue("namespace").trim()); //把mapper节点的nameSpace值存为接口名
            List<Function> list = new ArrayList<Function>(); //用来存储方法的List
            for(Iterator rootIter = root.elementIterator();rootIter.hasNext();) {//遍历根节点下所有子节点
                Function fun = new Function();    //用来存储一条方法的信息
                Element e = (Element) rootIter.next();
                String sqltype = e.getName().trim();
                String funcName = e.attributeValue("id").trim();
                String sql = e.getText().trim();
                String resultType = e.attributeValue("resultType").trim();
                fun.setSqltype(sqltype);
                fun.setFuncName(funcName);
                Object newInstance=null;
                try {
                    newInstance = Class.forName(resultType).newInstance();
                } catch (InstantiationException e1) {
                    e1.printStackTrace();
                } catch (IllegalAccessException e1) {
                    e1.printStackTrace();
                } catch (ClassNotFoundException e1) {
                    e1.printStackTrace();
                }
                fun.setResultType(newInstance);
                fun.setSql(sql);
                list.add(fun);
            }
            mapper.setList(list);

        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return mapper;
    }

        /**
         *
         * TODO:非递归方式扫描指定文件夹下面的所有文件
         * @return ArrayList<Object>
         * @param folderPath 需要进行文件扫描的文件夹路径
         * @author 邪恶小先生（LQ）
         * @time 2017年11月3日
         */
        public static ArrayList<Object> scanFilesWithNoRecursion(String folderPath) throws Exception {
            File directory = new File(folderPath);
            if(!directory.isDirectory()){
                throw new Exception('"' + folderPath + '"' + " input path is not a Directory , please input the right path of the Directory. ^_^...^_^");
            }
            else{
                //首先将第一层目录扫描一遍
                File [] files = directory.listFiles();
                //遍历扫出的文件数组，如果是文件夹，将其放入到linkedList中稍后处理
                for(int i = 0; i < files.length; i ++){
                    if(files[i].isDirectory()){
                        queueFiles.add(files[i]);
                    }else{
                        //暂时将文件名放入scanFiles中
                        scanFiles.add(files[i].getAbsolutePath().replaceAll("\\\\", "/"));

                        String courseFile = directory.getCanonicalPath().replaceAll("\\\\", "/");
                        MapperBean mapperBean = readMapper(preffix+files[i].getAbsolutePath().replaceAll("\\\\", "/").replace(courseFile,"" ));
                        map.put(mapperBean.getInterfaceName(), mapperBean);
                    }
                }

                //如果linkedList非空遍历linkedList
                while(!queueFiles.isEmpty()){
                    //移出linkedList中的第一个
                    File headDirectory = queueFiles.removeFirst();
                    File [] currentFiles = headDirectory.listFiles();
                    for(int j = 0; j < currentFiles.length; j ++){
                        if(currentFiles[j].isDirectory()){
                            //如果仍然是文件夹，将其放入linkedList中
                            queueFiles.add(currentFiles[j]);
                        }else{
                            scanFiles.add(currentFiles[j].getAbsolutePath());
                        }
                    }
                }
            }

            return scanFiles;
        }


}